﻿using System;
using System.Collections.Generic;
using System.Linq;
using FileMonitor.Configuration.Prototype;
using FileMonitor.Configuration.Prototype.BizProcess;


namespace FileMonitor.Service.Prototype
{
    internal  class RunBizProcess
    {

        public FileMonitorBase Process { get; private set; }
        internal RunBizProcess(FileMonitorBase process)
        {
            this.Process = process;
            this.failureTasksCount = new Dictionary<Guid, int>();
            this._dicBizProcesses = new System.Collections.Generic.Dictionary<int, BizProcessBase>();
        }
        protected Dictionary<int, BizProcessBase> _dicBizProcesses;
        private Dictionary<Guid, int> failureTasksCount;
       
        public void CopyBizProcesses(Dictionary<int, BizProcessBase> sourceProcess)
        {
            if (this._dicBizProcesses == null)
            {
                this._dicBizProcesses = new Dictionary<int, BizProcessBase>();
            }
            this._dicBizProcesses.Clear();
            foreach (int key in sourceProcess.Keys)
            {
                this._dicBizProcesses.Add(key, sourceProcess[key].Copy());
                this._dicBizProcesses[key].Excuted += new BizProcessBase.ExcutedHander(FileMonitorBase_Excuted);
            }
            foreach (int key in this._dicBizProcesses.Keys)
            {
                if (this._dicBizProcesses.ContainsKey(key + 1))
                {
                    this._dicBizProcesses[key].NextBizProcess = this._dicBizProcesses[key + 1];
                }
            }
        }

        public void Start()
        {
            this._dicBizProcesses.ToList().ForEach(bizP =>
            {
                bizP.Value.StartWorkThread();
            });
        }

        public void Stop()
        {
            this._dicBizProcesses.ToList().ForEach(bizP =>
            {
                bizP.Value.StopWorkThread();
            });
        }

        void FileMonitorBase_Excuted(object sender, ExcutedEventArgs args)
        {
            if (args.Result == ExcutedResult.Successful)
            {
                UpdateBizSucessful(new Guid(args.Task.BatchId), args.NextStatus);
            }
            //When Biz runned failed,it will repeat 3 times.
            else if (args.Result == ExcutedResult.Failure)
            {
                Guid batchid = new Guid(args.Task.BatchId);
                if (this.failureTasksCount.Keys.Contains(batchid))
                {
                    int countTimes = this.failureTasksCount[batchid];
                    if (countTimes < 3)
                    {
                        NotifyRunBizProcess(args.Task);
                        this.failureTasksCount[batchid] = this.failureTasksCount[batchid] + 1;
                    }
                    else
                    {
                        UpdateBizFailure(batchid, -2);
                        this.failureTasksCount.Remove(batchid);
                    }
                }
                else
                {
                    NotifyRunBizProcess(args.Task);
                    this.failureTasksCount.Add(batchid, 1);
                }
            }
        }

        private void UpdateBizSucessful(Guid batchid, int status)
        {
            FileUtility.DBUtility.UpdateStatus(Process.exchangeDB, batchid, status);
        }

        private void UpdateBizFailure(Guid batchid, int status)
        {
            FileUtility.DBUtility.UpdateStatus(Process.exchangeDB, batchid, status);
        }

        public void NotifyRunBizProcess(ExcutedTask excutedTask)
        {
            if (excutedTask.BatchId == null)
            {
                throw new ArgumentException("Can't be null", "BatchId");
            }
            if (this._dicBizProcesses.Count > 0)
            {
                this._dicBizProcesses.First().Value.Enqueue(excutedTask);
            }
        }
    }
}
